#ifndef NODO_H
#define NODO_H

#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <memory>

using namespace std;

#include "tipo.h"
#include "tabla.h"


int nuevaEtq(void);
void prologo(Entrada e);
void epilogo(Entrada e);


/****************************************************************
La clase abstracta nodo provee la base para el árbol de
representación intermedio.

Las clases que hereden Nodo deban implementar las funciones 
generar(void)

La función generar(void) ha de generar el código ensamblador
correspondiente al nodo implementado.

La función estática etiqueta y la variable estática int sirven 
para generar etiquetas con números de serie consecutivos. Los usan 
los nodos if y ifelse.
****************************************************************/
class Nodo {



 public:
  /*
  Necesitamos el constructor por defecto para poder inicializar nodos sin tipo inicialmente
  */
  Nodo(){}
  /*
  EL constructor que admite un puntero a un tipo nos permite inicializar aquellos nodos que
  tienen un tipo determinado implícitamente
  */
  Nodo(Tipo *tipo) : tipoNodo(tipo) {}

  virtual ~Nodo() {}
  virtual void generar(void) = 0;

  /*
  El campo tipoNodo almacena el tipo del nodo
  */
  CampoTipo tipoNodo;
  
  static string etiqueta(void);

  /*
  Genera el código máquina necesario para convertir el contenido de %eax
  supuesto entero, en un valor equivalente char, quedando éste en %al
  */
  void int2char();


 private:
  static int cont;

} ; // fin de la clase abstracta Nodo


/*****************************************************************
Definimos el tipo "CampoNodo" como un objeto del tipo 
std::auto_ptr de Nodo, que provee de "recolección de basura" para
los nodos hospedados en este campo.
****************************************************************/
typedef std::auto_ptr<Nodo> CampoNodo;


/*****************************************************************
Definimos el tipo "ListaParametros" como un objeto de vectores a 
punteros a objetos Nodo.
****************************************************************/
typedef std::vector<Nodo*> ListaParametros;


/*****************************************************************
NodoSecuencia representa una secuencia de nodos, que han de generarse
en según el orden de aparición en la gramática.
*****************************************************************/
class NodoSecuencia: public Nodo {
 private:
  CampoNodo sec, secs;
 public:
  NodoSecuencia(Nodo *sc,Nodo *scs) : sec(sc),secs(scs){}
  void generar(void);
}; // fin de la clase NodoSecuencia

/*****************************************************************
Implementa la construcción if, recibiendo una expresión de condición, y un
bloque de sentencias a ejecutar si se cumple la condición.
*****************************************************************/
class NodoIf: public Nodo {
 private:
  CampoNodo cond, cierto;
 public:
  NodoIf(Nodo *co,Nodo *i) :cond(co),cierto(i){}
  void generar(void);
}; // fin de la clase NodoIf

/*****************************************************************
Implementa la construcción if-else, recibiendo una expresión de condición, 
un bloque de sentencias a ejecutar si se cumple la condición, o otro a 
ejecutar si no se cumple
*****************************************************************/
class NodoIfElse: public Nodo {
 private:
  CampoNodo cond, cierto, falso;
 public:
  NodoIfElse(Nodo *co,Nodo *i,Nodo *e) :cond(co),cierto(i),falso(e){}
  void generar(void);
}; // fin de la clase NodoIf

/*****************************************************************
Implementa el salto incondicional de salida de función que devuelve 
un valor. Toma una expresión como ese valor
*****************************************************************/
class NodoRetorno: public Nodo {
 private:
  CampoNodo exp;
 public:
 NodoRetorno(Nodo *xp) : exp(xp){}
  void generar(void);
}; // fin de la clase NodoRetorno

/*****************************************************************
Implementa el salto incondicional de salida de función que no
devuelve ningun valor
*****************************************************************/
class NodoRetornoVacio: public Nodo {
 private:
  CampoNodo exp;
 public:
 NodoRetornoVacio() {}
 void generar(void);
}; // fin de la clase NodoRetorno



class NodoAsignacion : public Nodo {
 private:
  CampoNodo izq, expr;
 public:
  NodoAsignacion(Nodo *i, Nodo * e);
  void generar(void);
} ; // fin de la clase NodoAsignacion


/*****************************************************************
Implementa el nodo menos unario, que produce la negación entera 
expresión asociada
*****************************************************************/
class NodoMenosUnario: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoMenosUnario(Nodo* nod);
  void generar(void);
};

/*****************************************************************
Implementa el nodo más unario, que no produce ninguna modificación
a la expresión.
*****************************************************************/
class NodoMasUnario: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoMasUnario(Nodo* nod);
  void generar(void);
};


/*****************************************************************
Implementa el nodo incremento prefijo, que toma un nodo parte_izquierda,
lo incrementa, y lo devuelve incrementado 
*****************************************************************/
class NodoIncPrefijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoIncPrefijo(Nodo* nod);
  void generar(void);
};


/*****************************************************************
Implementa el nodo incremento prefijo, que toma un nodo parte_izquierda,
lo decrementa, y lo devuelve decrementado 
*****************************************************************/
class NodoDecPrefijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoDecPrefijo(Nodo* nod);
  void generar(void);
};



/*****************************************************************
Implementa el nodo incremento sufijo, que toma un nodo parte_izquierda,
lo incrementa, preo devuelve el valor original de la parte_izquierda
*****************************************************************/
class NodoIncSufijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoIncSufijo(Nodo* nod);
  void generar(void);
};



/*****************************************************************
Implementa el nodo decremento sufijo, que toma un nodo parte_izquierda,
lo decrementa, preo devuelve el valor original de la parte_izquierda
*****************************************************************/
class NodoDecSufijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoDecSufijo(Nodo* nod);
  void generar(void);
};



/*****************************************************************
Implementa el nodo suma, que recibe dos nodos, que corresponden a
expresiones
*****************************************************************/
class NodoSuma: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoSuma(Nodo* i, Nodo* d);
 void generar(void);
}; // fin de la clase NodoSuma



/*****************************************************************
Implementa el nodo resta, que recibe dos nodos, que corresponden a
expresiones
*****************************************************************/
class NodoResta: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoResta(Nodo* i, Nodo* d);
  void generar(void);
}; // fin de la clase NodoResta



/*****************************************************************
Implementa el nodo multiplicacion, que recibe dos nodos, que 
corresponden a expresiones
*****************************************************************/
class NodoMult: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoMult(Nodo* i, Nodo* d);
  void generar(void);
}; // fin de la clase NodoMult


/*****************************************************************
Implementa el nodo división, que recibe dos nodos, que 
corresponden a expresiones
*****************************************************************/
class NodoDivision: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoDivision(Nodo* i, Nodo* d);
  void generar(void);
}; // fin de la clase NodoDivision



/*****************************************************************
Implementa el nodo módulo (resto entero), que recibe dos nodos, que 
corresponden a expresiones
*****************************************************************/
class NodoModulo: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoModulo(Nodo* i, Nodo* d);
  void generar(void);
}; // fin de la clase NodoModulo



/*****************************************************************
Implementa el nodo llamada a función. Recive un nombre de función,
y una lista de parámetros.
*****************************************************************/
class NodoLlamada: public Nodo {
 public:
  NodoLlamada(string* nombre, ListaParametros* p);
  ~NodoLlamada();
  void generar(void);
 private:
  std::auto_ptr<string> nom;
  std::auto_ptr<ListaParametros> params;
}; // fin de la clase NodoLlamada


/*****************************************************************
Implementa el nodo constante literal del programa.
*****************************************************************/
class NodoConstanteChar: public Nodo {
 private:
  char caracter; 
 public:
 // Inicializamos el nodo constante entera como tipo entero
 NodoConstanteChar(char chrt): caracter(chrt), Nodo(new TipoChar()) {}
 void generar(void);
}; // fin de la clase NodoConstanteLiteral



/*****************************************************************
Implementa el nodo constante entera del programa.
*****************************************************************/
class NodoConstanteEntera: public Nodo {
 private:
  int num; 
 public:
 // Inicializamos el nodo constante entera como tipo entero
 NodoConstanteEntera(int numero): num(numero), Nodo(new TipoEntero()) {}
 void generar(void);
}; // fin de la clase NodoConstanteEntera



/*****************************************************************
Implementa el nodo constante de cadena. Guardamos las constantes
de cadena como un hash estático del propio NodoConstanteCadena.

La clave con la que guardamos la cadena es un número entero, y 
utilizamos un contador para ir generando dichas claves.

En constructor del nodo almacena la nueva cadena en el hash, quedando 
así disponible a través del campo "etiqueta" de la clase.

Posteriormente, la función main() del traductor, genera la sección
.rodata con recorriendo tablaCadenas.
*****************************************************************/
class NodoConstanteCadena: public Nodo {
 private:
  string * nom;
  int etiqueta;
  static int cont;
 public:
  NodoConstanteCadena(string * nombre): nom(nombre), Nodo(new TipoConstanteCadena()) {
      if(tablaCadenas.find(*nombre) == tablaCadenas.end()) {
           etiqueta = cont++;
           tablaCadenas[*nombre] = etiqueta;
      }
      else
	  etiqueta = tablaCadenas[*nombre];
      
  }
  void generar(void);
  static map<string,int> tablaCadenas; 
}; // fin de la clase NodoConstanteCadena



/*****************************************************************
Implementa la parte izquierda de una expresión de asignación. En nuestra
implementación, se corresponde con un identificador, que ya ha sido
declarado previamente en el programa.
*****************************************************************/
class NodoIdentificadorLVal : public Nodo {
 private:
  Entrada e;
 public:
 NodoIdentificadorLVal(Entrada pE);
 void generar(void);
} ; // fin de la clase NodoIdentificadorLVal



/*****************************************************************
Implementa el nodo vacío. No genera ningún código. Se produce cuando
el programados escribe varios puntos y coma seguidos.
*****************************************************************/
class NodoVacio : public Nodo {
 public:
  void generar(void);
} ; // fin de la clase NodoVacio

	
/*****************************************************************
Implementa el nodo "LValue". Toma una "parte_izquierda" y devuelve 
su valor como expresión.
*****************************************************************/
class NodoLValue: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoLValue(Nodo* nod);
  void generar(void);
}; 
#endif
